package yxy.game.pm2.bean;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.redisson.api.RMap;
import yxy.apple.logger.Logger;
import yxy.apple.util.FastJsonUtil;
import yxy.apple.util.RandomStringUtility;
import yxy.apple.util.redisson.RedisException;
import yxy.cherry.data.DataCenter;
import yxy.cherry.data.bean.herodata;
import yxy.cherry.data.bean.herolvcost;
import yxy.cherry.data.bean.herostagecost;
import yxy.cherry.game.base.mq.MqMessage;
import yxy.cherry.game.base.redis.RedisManager;
import yxy.game.pm2.bean.currency.Currencies;
import yxy.game.pm2.bean.currency.CurrencyType;
import yxy.game.pm2.bean.db.newDao.HeroDAO;
import yxy.game.pm2.bean.db.po.HeroPo;
import yxy.game.pm2.bean.module.BaseGameRedisLockBean;
import yxy.game.pm2.bean.mq.CCReason;
import yxy.game.pm2.bean.mq.MqMsg_CurrencyDecrease;
import yxy.game.pm2.bean.mq.MqMsg_CurrencyIncrease;
import yxy.game.pm2.bean.pubsub.HeroPackPublisher;
import yxy.game.pm2.bean.pubsub.HeroPublisher;

import java.util.*;
import java.util.stream.Collectors;

public class Hero extends BaseGameRedisLockBean {
	// bean===========================================================================
	private String code;// 编码
	private int dataId;// 数据id
	private int level;// 等级
	private int star;// 星级
	private int stage;// 阶数
	private int[] equips;
	private String soulA;// 龙魂A
	private String soulB;// 龙魂B
	private String magicA;// 兵法A
	private String magicB;// 兵法B
	private String magicC;// 兵法C

	private JSONObject propertyModule ;//jsonobject  数值

	private Long power;

	private boolean lock;// 锁定状态

	public JSONObject getPropertyModule() {
		return propertyModule;
	}

	public void setPropertyModule(JSONObject propertyModule) {
		this.propertyModule = propertyModule;
	}

	public Long getPower() {
		return power;
	}

	public void setPower(Long power) {
		this.power = power;
	}

	public static Logger getLogger() {
		return logger;
	}

	public static void setLogger(Logger logger) {
		Hero.logger = logger;
	}

	private LinkedList<Currencies> starUpCost = new LinkedList<>();

	public void setCode(String code) {
		this.code = code;
	}

	public String getCode() {
		return code;
	}

	public int getDataId() {
		return dataId;
	}

	public void setDataId(int dataId) {
		this.dataId = dataId;
	}

	public int getLevel() {
		return level;
	}

	public void setLevel(int level) {
		this.level = level;
	}

	public int getStar() {
		return star;
	}

	public void setStar(int star) {
		this.star = star;
	}

	public boolean isLock() {
		return lock;
	}

	public void setLock(boolean lock) {
		this.lock = lock;
	}

	public int getStage() {
		return stage;
	}

	public void setStage(int stage) {
		this.stage = stage;
	}

	public void setEquips(int[] equips) {
		this.equips = equips;
	}

	public int[] getEquips() {
		if (equips == null || equips.length < EquipPosition.values().length) {
			equips = new int[EquipPosition.values().length];
		}
		return equips;
	}

	public int getequip(EquipPosition pos) {
		return getEquips()[pos.getNumber()];
	}

	public int setequip(EquipPosition pos, int equipId) {
		int result = getEquips()[pos.getNumber()];
		equips[pos.getNumber()] = equipId;
		return result;
	}

	public String getSoulA() {
		return soulA;
	}

	public void setSoulA(String soulA) {
		this.soulA = soulA;
	}

	public String getSoulB() {
		return soulB;
	}

	public void setSoulB(String soulB) {
		this.soulB = soulB;
	}

	public String getMagicA() {
		return magicA;
	}

	public void setMagicA(String magicA) {
		this.magicA = magicA;
	}

	public String getMagicB() {
		return magicB;
	}

	public void setMagicB(String magicB) {
		this.magicB = magicB;
	}

	public String getMagicC() {
		return magicC;
	}

	public void setMagicC(String magicC) {
		this.magicC = magicC;
	}

	public LinkedList<Currencies> getStarUpCost() {
		return starUpCost;
	}

	public void setStarUpCost(LinkedList<Currencies> starUpCost) {
		this.starUpCost = starUpCost;
	}

	// func==========================================================================

	public Collection<Currency> trainAll() {
		Currencies all = new Currencies();
		all.add(levelUpCost(1, getLevel()));
		all.add(stageUpCost(0, getStage()));
		return all;
	}

	public String advancedCode() {
		return String.format("%s_%s", getDataId(), getStar());
	}

	/** 升级消耗 */
	static public Collection<Currency> levelUpCost(int min, int max) {
		Currencies cost = new Currencies();
		for (int i = min; i < max; i++) {
			herolvcost lvcost = DataCenter.getData(i, herolvcost.class);
			if (lvcost == null) {
				return cost;
			}
			cost.addAll(Currency.create(lvcost.getCosttype(), lvcost.getCostid(), lvcost.getCostnum()));
		}
		return cost;
	}

	/** 升阶消耗 */
	static public Collection<Currency> stageUpCost(int min, int max) {
		Currencies cost = new Currencies();
		for (int i = min; i < max; i++) {
			herostagecost _herostagecost = DataCenter.getData(i, herostagecost.class);
			if (_herostagecost == null) {
				return cost;
			}
			cost.addAll(Currency.create(_herostagecost.getCosttype(), _herostagecost.getCostid(), _herostagecost.getCostnum()));
		}
		return cost;
	}

	// redis==========================================================================

	static public String key(String playerCode) {
		return String.format("PLAYER:%s:HERO", playerCode);
	}

	static private RMap<String, Hero> touch(String playerCode) throws RedisException{
		RMap<String, Hero> map = RedisManager.client(redis()).getMap(key(playerCode));
		if (!map.isExists()) {
			List<HeroPo> all = HeroDAO.getList(playerCode);
			if (all.size() > 0) {
				for (HeroPo po : all) {
					map.put(po.getCode(), Hero.toBean(po));
				}
			}
		}
		return map;
	}

	static public void saveToDB(String playerCode) {
		try {
			long updateTime = System.currentTimeMillis();

			RMap<String, Hero> map = touch(playerCode);//Redis
			if (map.isExists()) {
				int count = 0;
				if (map.size() > 0) {
					List<HeroPo> collect = map.values().stream().map(e -> Hero.toDbBean(playerCode, e)).collect(Collectors.toList());
					HeroDAO.replace(collect, updateTime);
					count++;
				}

				if(count > 0) {//二次确认数据已经入库后，进行删除操作
					HeroDAO.delete(playerCode, updateTime);
				}
			}
		}catch (Exception e){
			e.printStackTrace();
		}
	}

	static public int size(String playerCode) {
		try {
			return touch(playerCode).size();
		} catch (RedisException e) {
		}
		return 0;
	}

	static public Map<String, Hero> all(String playerCode) {
		try {
			Map<String, Hero> heros = touch(playerCode).readAllMap();
			return heros;
		} catch (RedisException e) {
			e.printStackTrace();
		}
		return new HashMap<>();
	}

	static public Hero get(String playerCode, String code) {
		try {
			Hero hero = touch(playerCode).get(code);
			return hero;
		} catch (Exception e) {
			return null;
		}
	}

	static public boolean set(String playerCode, Hero hero) {
		try {
			RMap<String, Hero> heros = touch(playerCode);
			heros.put(hero.code, hero);
			HeroPublisher.getInstance().publish(playerCode, hero);
			return true;
		} catch (RedisException e) {
			e.printStackTrace();
			return false;
		}
	}

    //仅仅用于gm后台
	static public boolean set2(String playerCode, Hero hero) {
		try {
			RMap<String, Hero> heros = touch(playerCode);
			heros.put(hero.code, hero);
			return true;
		} catch (RedisException e) {
			e.printStackTrace();
			return false;
		}
	}


	private static Logger logger = Logger.create(Hero.class);

	/** 生成一个新武将 */
	static public Hero create(herodata data, String playerCode, CCReason reason) throws RedisException {
		return create(data, data.getStartcs(), playerCode, reason);
	}

	/** 生成一个新武将 */
	static public Hero create(herodata data, int star, String playerCode, CCReason reason) throws RedisException {
		String code = randomHeroCode();
		RMap<String, Hero> heros = touch(playerCode);
		while (heros.containsKey(code)) {
			code = randomHeroCode();
		}
		if (star < data.getStartcs()) {
			star = data.getStartcs();
		}

		Hero hero = new Hero();
		hero.setCode(code);
		hero.setDataId(data.getId());
		hero.setLevel(1);
		hero.setStar(star);
		hero.setStage(0);
		hero.setLock(false);

		set(playerCode, hero);

		stat_武将增加(playerCode, reason, hero);
		return hero;
	}

	static private String randomHeroCode() {
		return String.format("hh%s", RandomStringUtility.randomLowerNumeric(4));
	}

	/** 获得某一种武将的数量 */
	public static long getNumber(String playerCode, int dataId) {
		long number = 0;
		Map<String, Hero> all = all(playerCode);
		for (Hero hero : all.values()) {
			if (hero.getDataId() == dataId) {
				number++;
			}
		}
		return number;
	}

	public static Currency minus(String playerCode, int dataId) {
		// 武将不做减去处理
		return null;
	}

	public static void remove(String playerCode, Collection<String> codes, CCReason reason) {
		try {
			Map<String, Hero> heros = touch(playerCode);
			for (String code : codes) {
				Hero hero = heros.get(code);
				heros.remove(code);
				stat_武将减少(playerCode, reason, hero);
			}
			HeroPackPublisher.getInstance().publish(playerCode);
		} catch (RedisException e) {
			e.printStackTrace();
		}
	}

	public static void removeHeros(String playerCode, Collection<Hero> heros, CCReason reason) {
		try {
			Map<String, Hero> touch = touch(playerCode);
			ArrayList<String> list = new ArrayList<>();
			for (Hero hero : heros) {
				touch.remove(hero.getCode());
				list.add(hero.getCode());
				stat_武将减少(playerCode, reason, hero);
			}
			HeroPackPublisher.getInstance().publish(playerCode);
		} catch (RedisException e) {
			e.printStackTrace();
		}
	}

	public static void removeHero(String playerCode, Hero hero, CCReason reason) {
		try {
			Map<String, Hero> touch = touch(playerCode);
			touch.remove(hero.getCode());
			stat_武将减少(playerCode, reason, hero);
			HeroPackPublisher.getInstance().publish(playerCode);
		} catch (RedisException e) {
			e.printStackTrace();
		}
	}

	public static void removeAllFromRedis(String playerCode) throws RedisException {
		touch(playerCode).delete();
	}

	static private void stat_武将增加(String playerCode, CCReason reason, Hero hero) {
		PlayerBean playerBean = PlayerBean.get(playerCode);
		if (playerBean == null || reason == null || hero == null) {
			return;
		}
		MqMsg_CurrencyIncrease msg = new MqMsg_CurrencyIncrease();
		msg.setUid(playerBean.getUid());
		msg.setCode(playerBean.getCode());
		msg.setTime(new Date());
		msg.setServerid(playerBean.getServerId());

		msg.setReason(reason);
		Currency cur = Currency.create(CurrencyType.CT_武将, hero.getDataId(), 1);
		msg.setCurrency(cur);
		MqMessage.sendMessage(msg);
	}

	static private void stat_武将减少(String playerCode, CCReason reason, Hero hero) {
		PlayerBean playerBean = PlayerBean.get(playerCode);
		if (playerBean == null || reason == null || hero == null) {
			return;
		}
		MqMsg_CurrencyDecrease msg = new MqMsg_CurrencyDecrease();
		msg.setUid(playerBean.getUid());
		msg.setCode(playerBean.getCode());
		msg.setTime(new Date());
		msg.setServerid(playerBean.getServerId());

		msg.setReason(reason);
		Currency cur = Currency.create(CurrencyType.CT_武将, hero.getDataId(), 1);
		msg.setCurrency(cur);
		MqMessage.sendMessage(msg);
	}

	// lock==========================================================================

	static public String lockKey(String playerCode) {
		return String.format("lock:%s", key(playerCode));
	}

	static public boolean lockHero(String playerCode) throws InterruptedException {
		return tryLock(lockKey(playerCode));
	}

	static public void unlockHero(String playerCode) {
		unlock(lockKey(playerCode));
	}

	public static Hero toBean(HeroPo heroPo) {
		Hero u = new Hero();
		u.setCode(heroPo.getCode());
		u.setDataId(heroPo.getDataId());
		u.setLevel(heroPo.getLevel());
		u.setStar(heroPo.getStar());
		u.setStage(heroPo.getStage());
		String equips = heroPo.getEquips();
		u.setEquips(JSONArray.parseObject(equips, int[].class));
		u.setSoulA(heroPo.getSoulA());
		u.setSoulB(heroPo.getSoulB());
		u.setMagicA(heroPo.getMagicA());
		u.setMagicB(heroPo.getMagicB());
		u.setMagicC(heroPo.getMagicC());
		u.setLock(heroPo.isLock());
		String starUpCost = heroPo.getStarUpCost();
		List<Currencies> currencies = JSON.parseArray(starUpCost, Currencies.class);
		u.setStarUpCost(new LinkedList<>(currencies));
		return u;
	}

	public static HeroPo toDbBean(String playerCode, Hero hero) {
		HeroPo u = new HeroPo();
		u.setpCode(playerCode);
		u.setCode(hero.getCode());
		u.setDataId(hero.getDataId());
		u.setLevel(hero.getLevel());
		u.setStar(hero.getStar());
		u.setStage(hero.getStage());
		u.setEquips(Arrays.toString(hero.getEquips()));
		u.setSoulA(hero.getSoulA());
		u.setSoulB(hero.getSoulB());
		u.setMagicA(hero.getMagicA());
		u.setMagicB(hero.getMagicB());
		u.setMagicC(hero.getMagicC());
		u.setLock(hero.isLock());
		u.setStarUpCost(FastJsonUtil.bean2Json(hero.getStarUpCost()));
		return u;
	}
}
